package com.lxk.controller;

import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import com.lxk.pojo.Orders;
import com.lxk.service.GoodsService;
import com.lxk.service.OrdersService;
import com.lxk.service.RefundService;
import com.lxk.vo.result.CodeMsg;
import com.lxk.vo.result.Result;
import com.lxk.weixin.MyWxPayConfig;
import com.lxk.weixin.MyWxPayUtil;
import com.lxk.weixin.WxAESUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * @author JohnSoybean
 * @create 2020/3/31 11:17
 * @description 微信支付相关
 */
@Controller
@RequestMapping("/wxpay")
public class WxPayController {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private OrdersService os;
    @Autowired
    private RefundService rs;
    @Autowired
    private GoodsService gs;

    /**
     * 返回成功xml
     */
    private String resSuccessXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";

    /**
     * 返回失败xml
     */
    private String resFailXml = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[报文为空]]></return_msg></xml>";

    /**
     * 发起退款
     * @return
     */
    @PostMapping("/refund/orders")
    @ResponseBody
    public Result<Integer> requestOrdersRefund(Integer ordersId) {
        Map<String, String> data = new HashMap<String, String>();
        data.put("appid", MyWxPayUtil.appid);
        data.put("mch_id", MyWxPayUtil.mchid);
        data.put("nonce_str", MyWxPayUtil.getNonceStr());
        data.put("notify_url", MyWxPayUtil.notify_url);
        //插入订单信息
        log.info("发起退款订单号："+ordersId);
        Orders orders = os.selOrdersById(ordersId);
        if (orders==null) {
            return Result.error(CodeMsg.ORDER_NOT_EXIST);
        }
        data.put("out_trade_no", orders.getOutTradeNo());
        data.put("out_refund_no", MyWxPayUtil.getOutRefundNo());
        data.put("total_fee", String.valueOf(orders.getOrdersPrice()));
        data.put("refund_fee", String.valueOf(orders.getOrdersPrice()));
        //测试用
//        data.put("total_fee", String.valueOf(1));
//        data.put("refund_fee", String.valueOf(1));
        try {
            //生成签名
            String sign = WXPayUtil.generateSignature(data, MyWxPayUtil.key);
            data.put("sign", sign);
            MyWxPayConfig config =config = new MyWxPayConfig();
            WXPay wxpay = new WXPay(config, WXPayConstants.SignType.MD5, false);
            Map<String, String> returnMap = wxpay.refund(data);
            //判断结果
            String return_code = returnMap.get("return_code");
            String return_msg = returnMap.get("return_msg");
            if (return_code.equals("SUCCESS")) {
                String result_code = returnMap.get("result_code");
                if (result_code.equals("SUCCESS")) {
                    //TODO 成功业务逻辑
                    orders.setOrdersStatus(7);
                    os.updOrders(orders);
                    rs.generateRefundOrder(ordersId);

                    log.info("发起退款请求成功");
                    return Result.success(1);
                }else {
                    //TODO 失败业务逻辑

                    String err_code_des = returnMap.get("err_code_des");
                    log.info("发起退款请求失败,"+err_code_des);
                    return Result.error(CodeMsg.REFUND_ERROR.fillArgs(err_code_des));
                }

            }else {
                //TODO 失败业务逻辑

                log.info("发起退款请求失败");
                return Result.error(CodeMsg.REFUND_ERROR.fillArgs(return_msg));
            }

        } catch (Exception e) {
            //TODO 失败业务逻辑

            log.info("发起退款请求失败");
            e.printStackTrace();
            return Result.error(CodeMsg.WXPAY_CONFIG_ERR);
        }
    }


    /*
     * # 退款
     * 1. #修改订单支付状态及退款订单状态
     * 2. #返还优惠券
     * 3. #回退库存及销量
     * # 不进行：4. 回退用户积分、会员积分
     * # 不进行：5. 回退返利
     * # 不进行：卡券商品下单即收货，不能退款
     *
     */
    /**
     * 退款结果回调
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/afterrefund", produces = {"application/xml; charset=UTF-8"})
    @ResponseBody
    public void refundNotify(HttpServletRequest request, HttpServletResponse response) {
        String resXml = "";
        InputStream inStream;
        try {
            inStream = request.getInputStream();
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            log.info("微信退款回调:----start----");

            // 获取微信调用我们notify_url的返回信息
            String result = new String(outSteam.toByteArray(), "utf-8");
            log.info("微信退款回调:----result----=" + result);

            // 关闭流
            outSteam.close();
            inStream.close();

            // xml转换为map
            Map<String, String> map = WXPayUtil.xmlToMap(result);
            if (WXPayConstants.SUCCESS.equalsIgnoreCase(map.get("return_code"))) {

                log.info("微信退款回调:----返回成功----");

                /** 以下字段在return_code为SUCCESS的时候有返回： **/
                // 加密信息：加密信息请用商户秘钥进行解密，详见解密方式
                String req_info = map.get("req_info");

                /**
                 * 解密方式
                 * 解密步骤如下：
                 * （1）对加密串A做base64解码，得到加密串B
                 * （2）对商户key做md5，得到32位小写key* ( key设置路径：微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 )
                 * （3）用key*对加密串B做AES-256-ECB解密（PKCS7Padding）
                 */
                String resultStr = WxAESUtil.decryptData(req_info);

                log.info("微信退款回调:----解密结果----\r\n" + resultStr);
                Map<String, String> aesMap = WXPayUtil.xmlToMap(resultStr);

                /** 以下为返回的加密字段： **/
                String out_trade_no = aesMap.get("out_trade_no");
                String refund_status = aesMap.get("refund_status");

                // 退款是否成功
                if (!WXPayConstants.SUCCESS.equals(refund_status)) {
                    resXml = resFailXml;
                    log.info("微信退款回调:退款失败！");
                    //TODO 失败业务逻辑
                    Orders orders = os.selOrdersByOutTradeNo(out_trade_no);
                    if (orders != null) {
                        //判断是否重复处理业务逻辑
                        Integer ordersStatus = orders.getOrdersStatus();
                        if (ordersStatus.equals(7)) {
                            //修改订单状态
                            orders.setOrdersStatus(9);
                            os.updOrders(orders);
                            rs.changeRefundStatus(orders.getOrdersId(), 3);
                        }
                    }
                } else {
                    resXml = resSuccessXml;
                    log.info("微信退款回调:退款成功！");
                    //TODO 成功业务逻辑
                    Orders orders = os.selOrdersByOutTradeNo(out_trade_no);
                    if (orders != null) {
                        //判断是否重复处理业务逻辑
                        Integer ordersStatus = orders.getOrdersStatus();
                        if (ordersStatus.equals(7)) {
                            orders.setOrdersStatus(8);
                            os.updOrders(orders);
                            rs.changeRefundStatus(orders.getOrdersId(), 2);
                            //返还优惠券
                            rs.rollbackCoupon(orders.getOrdersId());
                            //回退库存及销量
                            Integer goodsId = orders.getGoodsId();
                            Integer goodsCount = orders.getGoodsCount();
                            gs.addGoodsStock(goodsId, goodsCount);
                        }
                    }
                }

            } else {
                log.error("微信退款回调:回调失败,错误信息：" + map.get("return_msg"));
                resXml = resFailXml;
            }

        } catch (Exception e) {
            log.error("refund:微信退款回调：发生异常：", e);
        } finally {
            try {
                // 处理业务完毕
                BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
                out.write(resXml.getBytes());
                out.flush();
                out.close();
            } catch (IOException e) {
                log.error("微信退款回调：发生异常：", e);
            }
        }
    }

}
